package com.amos.isearch.config;

import com.amos.isearch.dao.Sku;
import com.amos.isearch.dao.SkuRepository;
import com.hankcs.lucene.HanLPIndexAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MMapDirectory;
import org.apache.lucene.util.IOUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/**
 * DESCRIPTION: 数据初始化
 *
 * @author <a href="mailto:daoyuan0626@gmail.com">amos.wang</a>
 * @date 2021/1/24
 */
@Component
public class DataInit {

    @Resource
    private SkuRepository skuRepository;

    /**
     * 1. 分词器
     */
    private static final Analyzer ANALYZER = new HanLPIndexAnalyzer();
    /**
     * 索引存放位置
     */
    private static final Path INDEX_PATH = Path.of("DATA/index");

    private static volatile Directory directory;


    public void initIndex() {
        // 删除旧的索引文件
        cleanIndex();

        // 获取要构建索引的数据
        List<Sku> skus = initData();

        System.out.println("开始创建索引...");
        long begin = System.currentTimeMillis();
        try {
            index(skus);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.printf("创建索引完成 :: [%s]秒\n", (System.currentTimeMillis() - begin) / 1000);
        }
    }

    /**
     * 删除旧的索引文件
     */
    public void cleanIndex() {
        try {
            IOUtils.rm(INDEX_PATH);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("旧的索引文件已删除");
        }
    }

    /**
     * 创建索引
     */
    private static void index(List<Sku> skus) throws Exception {
        // 3. 创建分词器配置
        IndexWriterConfig config = new IndexWriterConfig(ANALYZER);
        // 4. 创建输出流对象
        IndexWriter indexWriter = new IndexWriter(getDirectory(), config);

        for (Sku sku : skus) {
            Document doc = new Document();
            // 不分词 索引 存储
            doc.add(new StringField("id", sku.getId(), Field.Store.YES));
            // 分词 索引 存储
            doc.add(new TextField("name", sku.getName(), Field.Store.YES));
            // 分词、索引（要范围查询所以需要分词+索引）
            // 价格需要存储（数值类型要存储，需要加一下 StoredField）
            doc.add(new IntPoint("price", sku.getPrice()));
            doc.add(new StoredField("price", sku.getPrice()));

            // 不分词 不索引 存储
            doc.add(new StoredField("image", sku.getImage()));
            // 不分词 索引 存储
            doc.add(new StringField("categoryName", sku.getCategoryName(), Field.Store.YES));
            // 不分词 索引 存储
            doc.add(new StringField("brandName", sku.getBrandName(), Field.Store.YES));

            indexWriter.addDocument(doc);
        }

        indexWriter.close();
    }

    /**
     * 创建 Directory 文件夹，对应索引库位置
     *
     * @return Directory
     * @throws Exception IOException
     */
    private static Directory getDirectory() throws Exception {
        if (directory == null) {
            synchronized (Directory.class) {
                if (directory == null) {
                    if (Files.notExists(INDEX_PATH)) {
                        Files.createDirectories(INDEX_PATH);
                    }

                    directory = MMapDirectory.open(INDEX_PATH);
                }
            }
        }

        return directory;
    }


    private List<Sku> initData() {
        long begin = System.currentTimeMillis();
        List<Sku> all = skuRepository.findAll();
        System.out.println("总数据量 :: " + all.size());
        System.out.printf("查询耗时 :: [%s]秒\n", (System.currentTimeMillis() - begin) / 1000);

        return all;
    }

}
